package test;

import com.tofacebook.spring.model.Dept;
import com.tofacebook.spring.model.Emp;
import com.tofacebook.spring.model.FatherDept;
import com.tofacebook.spring.model.SonDept;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@Slf4j
public class xmlControlJavaBean {
    /***
     * 通过Ioc容器获取我们再xml中配置Dept实体类
     *
     */
    @Test
    public void getDeptClassByIOC(){
        /**
         * 获取IOC的方式有两种
         * 第一种：通过FileSystemXmlApplicationContext
         * applicationContext.xml具体的文件存储路径在哪里
         * 相当于在 E:\softpeixun\s3\b322ban\mybatis-spring-springMvc\spring-series\spring-encounter\src\main\resources\
         *
         * 第二种：类路径去获取二进制文件applicationContext.xml
         *  ClassPathXmlApplicationContext("applicationContext.xml")
         *  获取配置文件的bean ,然后spring IOC会通过反射的机制
         *  Class.forName("类的全路径").newInstance()实例化我们对象，最后我们
         *  就得到一个类对象
         *
         */

        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        //ioc.getBean(bean的id) 会得到一个Object对象  ，那么需要强转成对应实体类
        Dept dept = (Dept)ioc.getBean("dept");//强转成对应实体类Dept
        dept.readDept();//通过对象的实例名去访问对象的成员属性和成员方法
    }

    /**
     * 获取javabean的三种方式
     * 1.通过配置文件中的bean的id去获取
     * 2.根据class类型去获取
     *    a.如果说在xml配置文件有两个同一个class 但是id不一样，
     *    就会导致获取Javabean时，不知道使用那个class
     *    就会报错： NoUniqueBeanDefinitionException: No qualifying bean
     *
     *    b.如果在xml配置如果class 没有去配置，但是在测试类又去获取该类，
     *    那么也会报错NoSuchBeanDefinitionException: No qualifying bean of type
     *
     *    c.spring ioc容器去加载xml文件获取对应的java bean 时候
     *    其实底层的原理就是根据反射的机制调用无参构造方法去实例化对象的
     *    如果在实体类中添加有参，但是不添加无惨的构造方法，那么就会有问题
     * 3.使用bean的id 和class类型一起使用获取javabean
     */
    @Test
    public void getDeptBeanClassByIOC(){
        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        //1 . ioc.getBean(bean的id) 会得到一个Object对象  ，那么需要强转成对应实体类
       /* Dept dept = (Dept)ioc.getBean("dept");//强转成对应实体类Dept
        dept.readDept();//通过对象的实例名去访问对象的成员属性和成员方法*/
        //2.使用class类型去获取对应的javabean ,是直接获取的，不需要强转
       /* Dept dept = ioc.getBean(Dept.class);//这是就不需要强转，直接获取的对应的实体类对象
        dept.readDept();*/
        //3.通过bean的id 和class类型去获取javabean
       /* Dept dept = ioc.getBean("dept",Dept.class);
        dept.readDept();*/
        //4.可不可使用接口类型来获取实现类的javabean呢？？
        /*
          这里要注意的地方是：接口不能作为bean 去在配置到applicationContext.xml，因为他是特殊的类：接口
         */
        Dept dept1 = (Dept)ioc.getBean(Dept.class);
        dept1.getSonDept();

        FatherDept fatherDept = (FatherDept) ioc.getBean(FatherDept.class);
        fatherDept.getSonDept();
    }

    @Test
    public void getDeptDI(){
        //1.  通过调用setter去对象属性去赋值
        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
        //Dept de = ioc.getBean("dept",Dept.class);
        /*
        log.info("通过调用setter去对象属性去赋值：{}",de);*/

        //2.  通过调用有参构造方法去给对象的属性赋值，首先需要在类中写对应的有参构造方法，然后需要在配置文件配置对应onstructor-arg value=
       // log.info("通过调用有参构造方法去给对象的属性赋值：{}",de);

        Emp emp = ioc.getBean("emp", Emp.class);
        log.info("给emp中的dept去赋值:{}",emp);
    }
}
